#include <stdio.h>
#include <float.h>
#include <ctype.h>
#include <time.h>
#include <stdlib.h>
#include "getputch.h"

#define RECORD_LEN 10     //记分榜长度长度

#define RECORD_TOP_LEN 3  //记录分榜中最高分长度

#define MAX_STAGE   10  //每次游戏进行次数

#define TIME_STRING_LEN 25

#define swap(type, a, b) do {type x=a; a=b; b=x;} while(0)

char dtfile[] = "LACKNUM.DAT";

typedef struct {
    int    type;    //0表示top记录 1表示recently记录
    time_t date;
    double score;
} Record;

char* showtime(time_t t)
{
    struct tm *loc = localtime(&t);

    static char show[TIME_STRING_LEN];
    sprintf(show, "%04d/%02d/%02d %02d:%02d:%02d", loc->tm_year + 1900, loc->tm_mon + 1, loc->tm_mday, loc->tm_hour, loc->tm_min, loc->tm_sec);

    return show;
}

time_t mmktime(int y, int m, int d, int h, int i, int s)
{
    struct tm t;

    t.tm_year = y - 1900;
    t.tm_mon = m - 1;
    t.tm_mday = d;
    t.tm_hour = h;
    t.tm_min = i;
    t.tm_sec = s;

    t.tm_isdst = -1;

    return mktime(&t);
}

void get_data(Record *recs)
{
    FILE* fp;

    if ((fp = fopen(dtfile, "r")) == NULL) {
        return;

    } else {
        int y, m, d, h, i, s,type;

        struct tm t;

        time_t date;
        double score;

        int j = 0;

        for (; j<RECORD_LEN; ++j) {
            Record r;
            int read;
            read = fscanf(fp, "%lf%d%d%d%d%d%d%d", &r.score, &y, &m, &d, &h, &i, &s, &r.type);

            if (read == EOF || read < 4) {
                break;
            }

            r.date = mmktime(y, m, d, h, i, s);
            recs[j] = r;

        }

        return ;
    }
}

void to_record(FILE *fp, const Record *res, int type)
{
    struct tm *local = localtime(&res->date);

    fprintf(fp,
            "%lf %d %d %d %d %d %d %d\n",
            res->score,
            local->tm_year + 1900,
            local->tm_mon+1,
            local->tm_mday,
            local->tm_hour,
            local->tm_min,
            local->tm_sec,
            type
            );
}

int put_data(double score)
{

    FILE *fp;
    time_t ti = time(NULL);

    Record recs[RECORD_LEN] = {0};

    get_data(recs);

    Record ins;
    ins.score = score;
    ins.date = ti;

    int i, j;

    if ((fp = fopen(dtfile, "w")) == NULL) {
        return 0;
    }

    Record *top[RECORD_TOP_LEN + 1];
    Record *recent[RECORD_LEN - RECORD_TOP_LEN];

    int t, r;
    t=r=0;

    for (int i=0; i<RECORD_LEN; ++i) {
        if (!recs[i].date) break;   //后面不会再有值

        if (recs[i].type == 0) {
            top[t++] = &recs[i];

        } else {
            recent[r++] = &recs[i];
        }

    }

    //对top使用插入排序
    i=0;
    for (;i<t; ++i) {
        //找到位置
        if (top[i]->score > ins.score) {
            for (j=t; j>i; --j) {
               top[j] = top[j-1];
            }

            top[i] = &ins;
            break;
        }
    }

    //表示j比前面的值都大 插入末尾
    if (i == t)
        top[i] = &ins;

    //保存top排行
    i=0;
    while (i <= t && i < RECORD_TOP_LEN) {
        to_record(fp, top[i++], 0);
    }

    //保存最近数据
    to_record(fp, &ins, 1);

    i=0;
    while (i < r && i < RECORD_LEN - RECORD_TOP_LEN - 1) {
        to_record(fp, recent[i++], 1);
    }

    if (0 != fclose(fp)) {
        fprintf(stderr, "Error in closing files\n");
    }

    return 1;
}

double go(void)
{
    int i, j;
    int stage;

    int dgt[] = {1,2,3,4,5,6,7,8,9};
    int a[8];

    time_t s,e;

    printf("请输入缺失的数字.\n");
    printf("按空格键开始.\n");
    fflush(stdout);

    while (getch() != ' ')
        ;


    time(&s);

    for (stage=0; stage<MAX_STAGE; ++stage) {
        int x =rand() % 9;

        for (j=i=0; i<9; i++) {
            if (x != i) {
                a[j++] = dgt[i];
            }
        }

        for (i=7; i>0; --i) {
            j = rand() % (i+1);
            swap(int, a[i], a[j]);
        }

        for (i=0; i<8; ++i) {
            printf("%d ", a[i]);
        }
        putch(':');

        int right;
        do {

            char no = getch();

            if (isprint(no)) {
                putch(no);

                right = no == '0' + dgt[x];

                if (!right) putch('\b');
                else putch('\n');
            }

        } while (!right);
    }

    time(&e);

    double dur = e - s;

    printf("用时%.1f.\n", dur);

    if (dur > 25) {
        printf("反应太慢了!");

    } else if (dur > 20) {
        printf("反应有点慢!");

    } else if (dur > 17) {
        printf("反应还行吧!");

    } else {
        printf("反应真快啊!");
    }

    putch('\n');

    return dur;
}

void print_record()
{
    int i;

    Record rec[RECORD_LEN] = {0};

    get_data(rec);

    puts("********************************");
    for (i=0; i<RECORD_LEN; ++i) {
        if (!rec[i].date) {
            break;
        }

        if (i == 0) {
            puts("Top:");

        } else if (rec[i].type != rec[i-1].type) {
            puts("\nRecent:");
        }


        printf("%6c %.2f %s\n", rec[i].type==0 ? '1'+i : ' ', rec[i].score, showtime(rec[i].date));
    }
    puts("*********************************");

    getch();
}

int main(void)
{
    int retry;
    double score;
    double best;

    init_getputch();

    srand(time(NULL));

    do {
        score = go();
        printf("正在保存数据...\n");
        put_data(score);

        printf("再来一次吗?...(0)否 (1)是: ");
        scanf("%d", &retry);

        putch('\n');

    } while (retry == 1);

    print_record();

    term_getputch();

    return 0;

}
